#include "os_cfg.h" 
    .text
    .global _start
    .extern kernel_init,init_main
    # void _start (boot_info_t * boot_info)
_start:
    # trans arg boot_info to func kernel_init
    # push %ebp
    # mov %esp,%ebp
    # mov 0x8(%ebp),%eax
    # pop %ebp
    mov 0x4(%esp),%eax
    # kernel_init(boot_info)
    push %eax
    call kernel_init
    jmp $KERNEL_SELECTOR_CS, $gdt_reload
gdt_reload:
    mov $KERNEL_SELECTOR_DS,%ax
	mov %ax,%ds
	mov %ax,%ss
	mov %ax,%es
	mov %ax,%fs
	mov %ax,%gs
    mov $(stack + KERNEL_STACK_SIZE),%esp
    jmp init_main

    .bss
.comm stack, KERNEL_STACK_SIZE

.macro exception_handler name num with_error_code
    .text
    .extern do_handler_\name
    .global exception_handler_\name
exception_handler_\name:
    .if \with_error_code == 0
        push $0
    .endif
    push $\num
    pusha
    push %ds
    push %es
    push %fs
    push %gs
    //stack arch:eflags,cs,eip,error_code,
    //           eax,ecx,edx,ebx,esp,ebp,esi,edi
    //           ds,es,fs,gs
    //           ret_addr
    push %esp
    call do_handler_\name
    //push %esp
    add $(1*4),%esp
    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa
    add $(2*4),%esp
    iret
.endm

exception_handler unknown, -1, 0
exception_handler divide_error,0, 0
exception_handler debug,1, 0
exception_handler nmi,2, 0
exception_handler breakpoint,3, 0
exception_handler overflow,4, 0
exception_handler bound_range_exceeded,5, 0
exception_handler invalid_opcode,6, 0
exception_handler device_not_available,7, 0
exception_handler double_fault,8, 1
//exception_handler coprocessor_segment_overrun,9, 0
exception_handler invalid_tss,10, 1
exception_handler segment_not_present,11, 1
exception_handler stack_segment_fault,12, 1
exception_handler general_protection_fault,13, 1
exception_handler page_fault,14, 1

exception_handler fpu_fault,16, 0
exception_handler alignment_check,17, 1
exception_handler machine_check,18, 0
exception_handler simd_floating_point,19, 0
exception_handler virtualization,20, 0
exception_handler control_protection,21, 1

exception_handler time,0x20, 0
exception_handler kbd,0x21,0
exception_handler disk_primary,0x2e,0
//exception_handler disk_secondary,0x2f,0
exception_handler mouse,0x74,0
//exception_handler syscall,0x80,0

//simple_switch(&from,to)
    .text
    .global simple_switch
simple_switch:
    # void simple_switch (uint32_t ** from, uint32_t * to)
    mov 4(%esp),%eax  // from
    mov 8(%esp),%edx  // to 
    # save registers
    push %ebp
    push %ebx
    push %esi
    push %edi
    mov %esp,(%eax)

    mov %edx,%esp  // to -> esp
    pop %edi
    pop %esi
    pop %ebx
    pop %ebp
    ret

 
    .global exception_handler_syscall
    .extern do_handler_syscall
exception_handler_syscall:
    pusha
    push %ds
    push %es
    push %fs
    push %gs
    pushf
    mov %esp,%eax
    push %eax

    call do_handler_syscall

    add $4,%esp
    popf
    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa

    retf $(5*4)